package org.dromara.web.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.NetbarConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.enums.FormatsType;
import org.dromara.common.core.utils.*;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.netbar.domain.bo.NetbarCouponMemberBo;
import org.dromara.netbar.domain.bo.NetbarMemberBo;
import org.dromara.netbar.domain.bo.NetbarMemberLogBo;
import org.dromara.netbar.domain.bo.NetbarMemberLoginBo;
import org.dromara.netbar.domain.vo.NetbarClientVo;
import org.dromara.netbar.domain.vo.NetbarCouponMemberVo;
import org.dromara.netbar.domain.vo.NetbarMemberVo;
import org.dromara.netbar.service.INetbarClientService;
import org.dromara.netbar.service.INetbarCouponMemberService;
import org.dromara.netbar.service.INetbarMemberLogService;
import org.dromara.netbar.service.INetbarMemberService;
import org.dromara.netbar.service.impl.CouponService;
import org.dromara.netbar.service.impl.MemberService;
import org.dromara.netbar.util.CouponUtils;
import org.dromara.system.service.ISysClientService;
import org.dromara.system.service.ISysConfigService;
import org.dromara.system.service.ISysSocialService;
import org.dromara.system.service.ISysTenantService;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
/**
 * 认证
 *
 * @author Lion Li
 */
@Slf4j
@SaIgnore
@RequiredArgsConstructor
@RestController
@RequestMapping("/auth/netbar")
public class AuthNetbarController {

    private final SocialProperties socialProperties;
    private final SysLoginService loginService;
    private final SysRegisterService registerService;
    private final ISysConfigService configService;
    private final ISysTenantService tenantService;
    private final ISysSocialService socialUserService;
    private final ISysClientService clientService;
    private final ScheduledExecutorService scheduledExecutorService;
    private final INetbarMemberService netbarMemberService;
    private final INetbarMemberLogService netbarMemberLogService;
    private final INetbarClientService netbarClientService;
    private final CouponService couponService;
    private final INetbarCouponMemberService netbarCouponMemberService;
    private final MemberService memberService;

    /**
     * 根据租户Id获取电脑列表
     */
    @GetMapping("/client/all/{tenantId}")
    public R<List<NetbarClientVo>> getClientAll(@PathVariable String tenantId) {
        return R.ok(netbarClientService.getClientAll(tenantId));
    }

    // 无授权根据身份证添加会员信息
    @PostMapping("/member/readCard")
    public R<?> memberReadCard(@Validated(AddGroup.class) @RequestBody NetbarMemberLogBo bo) {
        return netbarMemberLogService.insertByBo(bo)? R.ok() : R.fail("添加失败");
    }

    /**
     * 获取用户信息
     */
    @PostMapping("/member/info")
    public R<?> getMemberInfo(@RequestBody NetbarMemberBo bo) {
        AssertUtils.notNull(bo.getMemberId(), "账号信息有误");
        NetbarMemberVo netbarMemberVo = netbarMemberService.queryById(bo.getMemberId());
        String tenantId = netbarMemberVo.getTenantId();
        String memberRedisKey = tenantId + NetbarConstants.ONLINE_MEMBER_KEY;
        Map<String,Object> redisData = RedisUtils.getCacheMapValue(memberRedisKey, bo.getMemberId().toString());
        if (redisData == null) {
            return R.fail("账号已登出");
        }

        return R.ok(redisData);
    }

    /**
     * 预登录
     */
    @PostMapping("/member/preLogin")
    public R<?> preLogin(@RequestBody NetbarMemberLoginBo bo) {
        AssertUtils.notNull(bo.getAccount(), "请输入账号");
        AssertUtils.notNull(bo.getClientId(), "请选择电脑");
        AssertUtils.notNull(bo.getTenantId(), "租户信息有误");
        NetbarMemberVo member = netbarMemberService.getMember(bo.getTenantId(), bo.getAccount());
        AssertUtils.notNull(member, "该会员信息不存在");
        AssertUtils.isTrue(member.getPassword().equals(bo.getPassword()), "密码错误");
        AssertUtils.isTrue(!"0".equals(member.getStatus()), "请先在柜台进行激活");
        return couponService.getValidCoupons(bo);
    }

    /**
     * 登录
     */
    @PostMapping("/member/login")
    public R<?> loginClient(@Validated @RequestBody NetbarMemberLoginBo bo) {
        AssertUtils.notNull(bo.getAccount(), "请输入账号");
        AssertUtils.notNull(bo.getPassword(), "请输入密码");
        AssertUtils.notNull(bo.getClientId(), "请选择电脑");
        AssertUtils.notNull(bo.getTenantId(), "租户信息有误");
        NetbarMemberVo member = netbarMemberService.getMember(bo.getTenantId(), bo.getAccount());
        AssertUtils.notNull(member, "该会员信息不存在");
//        AssertUtils.isTrue("1".equals(member.getStatus()), "该会员已停用");
        AssertUtils.isTrue(member.getPassword().equals(bo.getPassword()), "密码错误");
        bo.setMemberId(member.getMemberId());
        String onlineMemberKey = RedisKeyGeneratorUtils.getOnlineMemberKey(bo.getTenantId());
        Map<String,Object> redisData = RedisUtils.getCacheMapValue(onlineMemberKey, member.getMemberId().toString());
        if(redisData != null){
            return R.ok("账号重连", redisData);
        }
        Map<String, Object> data = memberService.openClient(bo);
        //TODO 写入客户端登录日志
        if (data == null) {
            return R.fail("登录失败");
        }
        return R.ok("登录成功",data);
    }

    /**
     * 下机接口
     */
    @PostMapping("member/logout")
    public R<?> logout(@Validated @RequestBody NetbarMemberBo bo) {
        return R.ok(netbarMemberService.offline(bo));
    }

    /**
     * 检查在线会员
     * 1、先获取redis中所有的在线会员
     * 2、判断会员的余额是否充足
     * 3、余额不充足的会员，使用原子删除操作redis
     * 4、对数据库中该用户的余额进行扣除
     * 5、调取下机操作
     */
    @PostMapping("member/checkOnlineMembers")
    public R<?> checkOnlineMembers(@RequestBody NetbarMemberBo bo) {
        // 1、获取redis中所有的在线会员
        String memberRedisKey = RedisKeyGeneratorUtils.getOnlineMemberKey(bo.getTenantId());
        Map<String, Map<String, Object>> membersMap = RedisUtils.getCacheMap(memberRedisKey);
        if (membersMap == null || membersMap.isEmpty()) {
            return R.ok("无在线会员");
        }
        // 用于记录被处理的会员ID
        List<Long> processedMemberIds = new ArrayList<>();
        long currentTime = System.currentTimeMillis();
        Map<String, Object> member;
        long l;
        for (String memberKey : membersMap.keySet()) {
            member = membersMap.get(memberKey);
            l = memberService.checkOneMember(member, bo.getTenantId(), currentTime, false);
            if (0 != l && (-1) != l && (-2) != l) {
                processedMemberIds.add(l);
            }
        }

        if (processedMemberIds.isEmpty()) {
            return R.ok("所有在线会员余额充足，无需处理。");
        } else {
            return R.ok("检查完成，成功处理 " + processedMemberIds.size() + " 名的会员。", processedMemberIds);
        }
    }

    /**
     * 获取卡券
     */
    @PostMapping("/member/coupons")
    public R<?> couponList(@RequestBody NetbarMemberLoginBo bo) {
        AssertUtils.notNull(bo.getMemberId(), "会员ID不能为空");
        long currentTimeMillis = System.currentTimeMillis();
        String nowDateStr = DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, new Date());
        List<NetbarCouponMemberVo> netbarCouponMemberVos = netbarCouponMemberService.listCouponMemberGroupByMemberIds(Collections.singletonList(bo.getMemberId()), nowDateStr);
        for (NetbarCouponMemberVo cmRecord : netbarCouponMemberVos) {
            if(null != cmRecord.getCoupon() && CouponUtils.checkCouponBsValid(cmRecord.getCoupon(), currentTimeMillis)){
                cmRecord.setAvailable(true);
            }
        }
        Map<String, Object> resultMaps = new HashMap<>();
        // 自动使用优惠券
        resultMaps.put("autoCouponMemberList", netbarCouponMemberVos.stream().filter(c -> c.getCoupon().getIsAutoUse() == 1 && c.getMemberId().equals(bo.getMemberId())).toList());
        resultMaps.put("manualCouponMemberList", netbarCouponMemberVos.stream().filter(c -> c.getCoupon().getIsAutoUse() == 2 && c.getMemberId().equals(bo.getMemberId())).toList());
        return R.ok(resultMaps);
    }

    /**
     * 使用卡券
     * @param bo {memberId 用户Id,couponId 卡券Id}
     */
    @PostMapping("/member/useCoupon")
    public R<?> use(@RequestBody NetbarCouponMemberBo bo) {
        return couponService.useCoupon(bo);
    }

    @PostMapping("/member/coupons/valid")
    public R<?> couponValid(@RequestBody NetbarMemberLoginBo bo) {
        AssertUtils.notNull(bo.getMemberId(), "会员ID不能为空");
        AssertUtils.notNull(bo.getTenantId(), "租户ID不能为空");
        AssertUtils.notNull(bo.getClientId(), "电脑ID不能为空");
        return couponService.getValidCoupons(bo);
    }
}
